using Opc.Ua;
using OpcUaHelper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using twistmachinev2.CommonUse;

namespace twistmachinev2
{
    /// <summary>
    /// 动态OPC UA映射器，支持基于配置文件的动态属性映射
    /// </summary>
    public class DynamicOpcUaMapper
    {
        private readonly OpcUaClient opcUaClient;
        private readonly OpcUaConfigManager configManager;
        private readonly Dictionary<string, DynamicDataModel> dataModels;
        private readonly Dictionary<string, string> nodeToPropertyMapping; // NodeId -> PropertyName
        private readonly Dictionary<string, string> nodeToObjectMapping;   // NodeId -> ObjectName

        /// <summary>
        /// 数据变化事件
        /// </summary>
        public event Action<string, object> DataChanged;

        public DynamicOpcUaMapper(OpcUaClient client, OpcUaConfigManager config)
        {
            opcUaClient = client;
            configManager = config;
            dataModels = new Dictionary<string, DynamicDataModel>();
            nodeToPropertyMapping = new Dictionary<string, string>();
            nodeToObjectMapping = new Dictionary<string, string>();
        }

        /// <summary>
        /// 初始化动态映射
        /// </summary>
        public void Initialize()
        {
            var allNodes = configManager.GetAllNodes();

            // 按对象名分组
            var nodesByObject = allNodes.GroupBy(n => n.ObjectName ?? "Default");

            foreach (var objectGroup in nodesByObject)
            {
                string objectName = objectGroup.Key;
                var nodes = objectGroup.ToList();

                // 创建动态数据模型
                var dataModel = new DynamicDataModel();
                dataModel.Initialize(nodes);
                dataModels[objectName] = dataModel;

                // 建立映射关系
                foreach (var node in nodes)
                {
                    nodeToPropertyMapping[node.NodeId] = node.PropertyName;
                    nodeToObjectMapping[node.NodeId] = objectName;
                }
            }

            // 动态映射器初始化完成
        }

        /// <summary>
        /// 获取数据模型
        /// </summary>
        public DynamicDataModel GetDataModel(string objectName = "Default")
        {
            return dataModels.TryGetValue(objectName, out var model) ? model : null;
        }

        /// <summary>
        /// 获取所有数据模型
        /// </summary>
        public Dictionary<string, DynamicDataModel> GetAllDataModels()
        {
            return new Dictionary<string, DynamicDataModel>(dataModels);
        }

        /// <summary>
        /// 读取单个节点数据
        /// </summary>
        public async Task<OperateResult<object>> ReadNodeAsync(string nodeId)
        {
            var opcNodeId = new Opc.Ua.NodeId(nodeId);
            var result = await opcUaClient.ReadAsync(new Opc.Ua.NodeId[] { opcNodeId });
            if (result.IsSuccess && result.Content != null && result.Content.Length > 0)
            {
                UpdateModelProperty(nodeId, result.Content[0]);
                return new OperateResult<object>(result.Content[0]);
            }
            return new OperateResult<object>(result.Message);
        }

        /// <summary>
        /// 读取所有节点数据
        /// </summary>
        public async Task<OperateResult> ReadAllDataAsync()
        {
            // 只读取非订阅节点，避免与订阅机制冲突
            var allNodes = configManager.GetAllNodes();
            var nonSubscribedNodes = allNodes.Where(n => !n.IsSubscribed).ToList();
            var nodeIds = nonSubscribedNodes.Select(n => n.NodeId).ToArray();

            if (nodeIds.Length == 0)
            {
                // 所有节点都已订阅，跳过定时读取
                return new OperateResult();
            }

            // 定时读取非订阅节点

            // 将string[]转换为NodeId[]
            var opcNodeIds = nodeIds.Select(id => new Opc.Ua.NodeId(id)).ToArray();

            var result = await opcUaClient.ReadAsync(opcNodeIds);
            if (result.IsSuccess && result.Content != null)
            {
                for (int i = 0; i < nodeIds.Length && i < result.Content.Length; i++)
                {
                    // 定时读取数据
                    UpdateModelProperty(nodeIds[i], result.Content[i]);
                }
            }
            else
            {
                LogManager.LogError($"定时读取失败: {result.Message}");
            }

            return result.IsSuccess ? new OperateResult() : new OperateResult(result.Message);
        }

        /// <summary>
        /// 读取所有节点数据（用于初始化）
        /// </summary>
        public async Task<OperateResult> ReadAllNodesForInitAsync()
        {
            var allNodes = configManager.GetAllNodes();
            var nodeIds = allNodes.Select(n => n.NodeId).ToArray();

            if (nodeIds.Length == 0)
            {
                return new OperateResult("没有配置的节点");
            }

            // 初始化读取所有节点数据

            // 将string[]转换为NodeId[]
            var opcNodeIds = nodeIds.Select(id => new Opc.Ua.NodeId(id)).ToArray();

            var result = await opcUaClient.ReadAsync(opcNodeIds);
            if (result.IsSuccess && result.Content != null)
            {
                for (int i = 0; i < nodeIds.Length && i < result.Content.Length; i++)
                {
                    UpdateModelProperty(nodeIds[i], result.Content[i]);
                }
                // 初始化读取完成
            }
            else
            {
                LogManager.LogError($"初始化读取失败: {result.Message}");
            }

            return result.IsSuccess ? new OperateResult() : new OperateResult(result.Message);
        }

        /// <summary>
        /// 写入单个节点数据
        /// </summary>
        public async Task<OperateResult> WriteNodeAsync(string nodeId, object value)
        {
            // 根据节点配置进行类型转换
            var convertedValue = ConvertValueByNodeConfig(nodeId, value);

            var opcNodeId = new Opc.Ua.NodeId(nodeId);
            var result = await opcUaClient.WriteAsync(nodeId, convertedValue);
            if (result.IsSuccess)
            {
                UpdateModelProperty(nodeId, convertedValue);
            }
            return result;
        }

        /// <summary>
        /// 根据节点配置转换值类型
        /// </summary>
        private object ConvertValueByNodeConfig(string nodeId, object value)
        {
            try
            {
                // 查找节点配置
                var nodeConfig = configManager.GetAllNodes().FirstOrDefault(n => n.NodeId == nodeId);
                if (nodeConfig == null || string.IsNullOrEmpty(nodeConfig.DataType))
                {
                    return value; // 如果没有找到配置，返回原值
                }

                // 使用DynamicDataModel的类型转换逻辑
                return ConvertValue(value, nodeConfig.DataType);
            }
            catch
            {
                return value; // 转换失败时返回原值
            }
        }

        /// <summary>
        /// 值类型转换（与DynamicDataModel保持一致）
        /// </summary>
        private object ConvertValue(object value, string dataType)
        {
            if (value == null) return GetDefaultValue(dataType);

            try
            {
                if (string.IsNullOrEmpty(dataType))
                    return value;

                switch (dataType.ToLower())
                {
                    case "bool":
                    case "boolean":
                        return Convert.ToBoolean(value);
                    case "byte":
                        return Convert.ToByte(value);
                    case "short":
                    case "int16":
                        return Convert.ToInt16(value);
                    case "int":
                    case "int32":
                        return Convert.ToInt32(value);
                    case "long":
                    case "int64":
                        return Convert.ToInt64(value);
                    case "float":
                    case "single":
                        return Convert.ToSingle(value);
                    case "double":
                        return Convert.ToDouble(value);
                    case "decimal":
                        return Convert.ToDecimal(value);
                    case "string":
                        return value.ToString();
                    case "datetime":
                        if (value is DateTime)
                            return value;
                        else
                            return DateTime.Parse(value.ToString());
                    default:
                        return value;
                }
            }
            catch
            {
                return GetDefaultValue(dataType);
            }
        }

        /// <summary>
        /// 根据数据类型获取默认值
        /// </summary>
        private object GetDefaultValue(string dataType)
        {
            if (string.IsNullOrEmpty(dataType))
                return null;

            switch (dataType.ToLower())
            {
                case "bool":
                case "boolean":
                    return false;
                case "byte":
                    return (byte)0;
                case "short":
                case "int16":
                    return (short)0;
                case "int":
                case "int32":
                    return 0;
                case "long":
                case "int64":
                    return 0L;
                case "float":
                case "single":
                    return 0.0f;
                case "double":
                    return 0.0;
                case "decimal":
                    return 0.0m;
                case "string":
                    return string.Empty;
                case "datetime":
                    return DateTime.MinValue;
                default:
                    return null;
            }
        }

        /// <summary>
        /// 写入属性到OPC UA服务器
        /// </summary>
        public async Task<OperateResult> WritePropertyAsync(string objectName, string propertyName, object value)
        {
            var dataModel = GetDataModel(objectName);
            if (dataModel == null)
            {
                return new OperateResult($"未找到数据模型: {objectName}");
            }

            var nodeConfig = dataModel.GetNodeConfig(propertyName);
            if (nodeConfig == null)
            {
                return new OperateResult($"未找到属性配置: {propertyName}");
            }

            if (nodeConfig.AccessLevel != "Write" && nodeConfig.AccessLevel != "ReadWrite")
            {
                return new OperateResult($"属性 {propertyName} 不可写");
            }

            return await WriteNodeAsync(nodeConfig.NodeId, value);
        }

        /// <summary>
        /// 建立所有订阅
        /// </summary>
        public void EstablishAllSubscriptions()
        {
            var allNodes = configManager.GetAllNodes().Where(n => n.IsSubscribed).ToList();
            // 开始建立订阅

            int successCount = 0;
            foreach (var node in allNodes)
            {
                try
                {
                    SubscribeToNode(node);
                    successCount++;
                    // 成功订阅节点
                }
                catch (Exception ex)
                {
                    LogManager.LogError($"订阅节点失败: {node.NodeId} - {ex.Message}");
                }
            }

            // 订阅建立完成
        }

        /// <summary>
        /// 订阅单个节点
        /// </summary>
        private void SubscribeToNode(OpcUaNodeConfig nodeConfig)
        {
            var result = opcUaClient.Subscribe(nodeConfig.NodeId, (nodeId, value) =>
            {
                try
                {
                    // 收到订阅数据
                    // 收到订阅数据
                    UpdateModelProperty(nodeId, value);
                }
                catch (Exception ex)
                {
                    LogManager.LogError($"处理订阅数据时发生异常: {ex.Message}");
                }
            });
            
            if (!result.IsSuccess)
            {
                throw new Exception($"订阅失败: {result.Message}");
            }
        }

        /// <summary>
        /// 更新模型属性
        /// </summary>
        private void UpdateModelProperty(string nodeId, object value)
        {
            if (!nodeToPropertyMapping.TryGetValue(nodeId, out var propertyName) ||
                !nodeToObjectMapping.TryGetValue(nodeId, out var objectName))
            {
                // 未找到节点的映射配置
                // 未找到节点映射配置
                return;
            }

            if (!dataModels.TryGetValue(objectName, out var dataModel))
            {
                // 未找到数据模型
                // 未找到数据模型
                return;
            }

            // 更新模型属性
            bool success = dataModel.SetValue(propertyName, value);
            if (success)
            {
                // 已更新属性，触发数据变化事件
                // 触发DataChanged事件
                DataChanged?.Invoke(nodeId, value);
            }
            else
            {
                // 更新属性失败
                LogManager.LogError($"更新属性失败: {objectName}.{propertyName} (NodeId: {nodeId})");
            }
        }

        /// <summary>
        /// 取消所有订阅
        /// </summary>
        public void UnsubscribeAll()
        {
            var allNodes = configManager.GetAllNodes();
            foreach (var node in allNodes)
            {
                opcUaClient.Unsubscribe(node.NodeId);
            }
            // 已取消所有订阅
        }

        /// <summary>
        /// 获取映射信息
        /// </summary>
        public Dictionary<string, string> GetMappingInfo()
        {
            var info = new Dictionary<string, string>();
            foreach (var kvp in nodeToPropertyMapping)
            {
                var objectName = nodeToObjectMapping[kvp.Key];
                info[kvp.Key] = $"{objectName}.{kvp.Value}";
            }
            return info;
        }

        /// <summary>
        /// 获取指定对象的所有属性值
        /// </summary>
        public Dictionary<string, object> GetObjectValues(string objectName = "Default")
        {
            var dataModel = GetDataModel(objectName);
            return dataModel?.ToDictionary() ?? new Dictionary<string, object>();
        }

        /// <summary>
        /// 设置指定对象的属性值
        /// </summary>
        public void SetObjectValues(string objectName, Dictionary<string, object> values)
        {
            var dataModel = GetDataModel(objectName);
            dataModel?.FromDictionary(values);
        }

        /// <summary>
        /// 写入指定对象的属性到OPC UA服务器
        /// </summary>
        /// <param name="objectName">对象名称</param>
        /// <param name="propertyName">属性名称</param>
        /// <returns>操作结果</returns>
        public async Task<OperateResult> WritePropertyAsync(string objectName, string propertyName)
        {
            var dataModel = GetDataModel(objectName);
            if (dataModel == null)
            {
                return new OperateResult($"未找到对象: {objectName}");
            }

            var value = dataModel.GetValue(propertyName);
            return await WritePropertyAsync(objectName, propertyName, value);
        }

        /// <summary>
        /// 写入指定对象的所有属性到OPC UA服务器
        /// </summary>
        /// <param name="objectName">对象名称</param>
        /// <returns>操作结果</returns>
        public async Task<OperateResult> WriteAllPropertiesAsync(string objectName)
        {
            var dataModel = GetDataModel(objectName);
            if (dataModel == null)
            {
                return new OperateResult($"未找到对象: {objectName}");
            }

            try
            {
                var objectNodes = configManager.GetNodesByObject(objectName);
                if (objectNodes == null || !objectNodes.Any())
                {
                    return new OperateResult($"未找到对象 {objectName} 的节点配置");
                }

                var nodeIds = new List<string>();
                var values = new List<object>();

                foreach (var node in objectNodes)
                {
                    if (!string.IsNullOrEmpty(node.PropertyName))
                    {
                        var value = dataModel.GetValue(node.PropertyName);
                        if (value != null)
                        {
                            nodeIds.Add(node.NodeId);
                            values.Add(value);
                        }
                    }
                }

                if (nodeIds.Count > 0)
                {
                    //var result = await opcUaClient.WriteAsync(nodeIds.ToArray(), values.ToArray());
                    //return result;

                    for (int i = 0; i < nodeIds.Count; i++)
                    {
                        OperateResult result = await WriteNodeAsync(nodeIds[i], values[i]);
                        if (!result.IsSuccess)
                        {
                            // 如果任何一个节点写入失败，则返回失败结果
                            return new OperateResult($"节点 {nodeIds[i]} 写入失败");
                        }
                    }

                    return new OperateResult(); // 所有节点写入成功
                }
                else
                {
                    return new OperateResult("没有找到可写入的属性");
                }
            }
            catch (Exception ex)
            {
                return new OperateResult($"写入所有属性时发生错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 根据属性名称批量写入节点数据
        /// </summary>
        /// <param name="propertyValues">属性名称和值的字典</param>
        /// <returns>操作结果</returns>
        public async Task<OperateResult> WritePropertiesByNameAsync(Dictionary<string, object> propertyValues)
        {
            if (propertyValues == null || propertyValues.Count == 0)
            {
                return new OperateResult("属性值字典不能为空");
            }

            try
            {
                var allNodes = configManager.GetAllNodes();
                var successCount = 0;
                var totalCount = propertyValues.Count;
                var errors = new List<string>();

                foreach (var kvp in propertyValues)
                {
                    string propertyName = kvp.Key;
                    object value = kvp.Value;

                    // 根据属性名称查找对应的节点配置
                    var nodeConfig = allNodes.FirstOrDefault(n => n.PropertyName == propertyName);
                    if (nodeConfig == null)
                    {
                        errors.Add($"未找到属性名称 '{propertyName}' 对应的节点配置");
                        continue;
                    }

                    // 检查节点是否可写
                    if (!nodeConfig.CanWrite)
                    {
                        errors.Add($"节点 '{nodeConfig.NodeId}' (属性: {propertyName}) 不可写");
                        continue;
                    }

                    // 使用现有的WriteNodeAsync方法进行写入（包含类型转换）
                    var result = await WriteNodeAsync(nodeConfig.NodeId, value);
                    if (result.IsSuccess)
                    {
                        successCount++;
                    }
                    else
                    {
                        errors.Add($"写入属性 '{propertyName}' (节点: {nodeConfig.NodeId}) 失败: {result.Message}");
                    }
                }

                // 返回结果
                if (successCount == totalCount)
                {
                    return new OperateResult(); // 全部成功
                }
                else if (successCount > 0)
                {
                    return new OperateResult($"部分成功: {successCount}/{totalCount} 个属性写入成功。错误: {string.Join("; ", errors)}");
                }
                else
                {
                    return new OperateResult($"全部失败: {string.Join("; ", errors)}");
                }
            }
            catch (Exception ex)
            {
                return new OperateResult($"批量写入属性时发生错误: {ex.Message}");
            }
        }
    }
}